package se.mushroomwars.network.protocol;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.HashMap;



public class ReadData {
	HashMap<SocketChannel, Holder> map;
	
	private class Holder {
		private int curLen;
		private PackageHeader header;
		private ByteBuffer data;
		//used in ReadData
		private boolean readHeader;

		public Holder() {
			curLen = 0;
			readHeader = true;
		}
	}

	public ReadData() {
		map = new HashMap<SocketChannel, Holder>();
	}
	
	private Object byteToObject(byte[] data) throws IOException,
	ClassNotFoundException {
		ByteArrayInputStream bis = new ByteArrayInputStream(data);
		ObjectInputStream ois = new ObjectInputStream(bis);
		return ois.readObject();
}

	public Object getData(SocketChannel socket) throws IOException,
			ClassNotFoundException {
		ByteBuffer buf = map.get(socket).data;
		buf.position(0);
		return byteToObject(buf.array());
	}

	public int getPackageID(SocketChannel socket) {
		return map.get(socket).header.getPackageID();
	}

	public int getPackageLength(SocketChannel socket) {
		return map.get(socket).header.getPackageLength();
	}

	public Object read(SocketChannel socket) throws IOException,
			ClassNotFoundException {
		//SocketChannel socket = (SocketChannel) key.channel();
		ByteBuffer databuf = null;
		int packageLen = 0;
		// makes sure the object exist in the map before trying to reach it
		if (!map.containsKey(socket))
			map.put(socket, new Holder());
		Holder curHolder = map.get(socket);

		// we are not reading a package = this is a new package, read header
		if (curHolder.readHeader == true) {
			curHolder.readHeader = false;

			ByteBuffer buf = ByteBuffer.allocate(PackageHeader.HEADER_LENGTH);
			int n = socket.read(buf);
			// client disconnected or missformed header
			if (n == -1 || n != PackageHeader.HEADER_LENGTH) {
				map.remove(socket);
				throw new IOException();
			}

			PackageHeader curHeader = new PackageHeader();
			curHeader.decodeHeader(buf.array());
			curHolder.header = curHeader;
			packageLen = curHolder.header.getPackageLength();
			if (packageLen < 0) {
				map.remove(socket);
				throw new IOException();
			}

			curHolder.data = (ByteBuffer.allocate(packageLen));
		}

		// allocate space for the remaning package
		databuf = ByteBuffer.allocate(curHolder.header.getPackageLength()
				- curHolder.curLen);
		int n = socket.read(databuf);
		curHolder.curLen += n;
		databuf.position(0);
		curHolder.data.put(databuf);
		// the whole package is read
		if (n >= packageLen) {
			curHolder.curLen = 0;
			curHolder.readHeader = true;
			return getData(socket);
			// tell server that the data is ready
		}
		return null;
	}
}
